#pragma once
#ifndef _THREAD_POOL_HPP_
#define _THREAD_POOL_HPP_

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"

const int g_thread_num = 3;

using namespace std;
// 本质生产消费模型
template <class T>
class ThreadPool
{
public:
    pthread_mutex_t *GetMutex()
    {
        return &_lock;
    }

    bool IsEmpty()
    {
        return _task_queue.empty();
    }

    void waitCond()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    T GetTask()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

private:
    ThreadPool(int thread_num = g_thread_num)
        : _num(thread_num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);

        for (int i = 0; i < _num; i++)
        { // 进入构造函数大括号内就已经分配号空间了，所以可以用this指针
            _threads.push_back(new Thread(i, routine, this));
        }
    }
    ThreadPool(const ThreadPool<T> &other) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;

public:
    // 创造单例模式（懒汉模式）
    static ThreadPool<T> *getThreadPool(int num = g_thread_num)
    {
        // 可以有效减少未来必定要进行加锁检测的问题
        // 拦截大量的在已经创建好单例的时候，剩余线程请求单例的而直接访问锁的行为
        if (nullptr == _thread_ptr)
        {
            lockGuard lockguard(&_mutex); // 确保
            if (nullptr == _thread_ptr)   // 未创建
            {
                // 但是，未来任何一个线程想获取单例，都必须调用getThreadPool接口
                // 但是，一定会存在大量的申请和释放锁的行为，这个是无用且浪费资源的
                _thread_ptr = new ThreadPool<T>(num);
            }
        }
        return _thread_ptr;
    }

    static void *routine(void *args) // 不包含this指针
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args;
        //_task_queue.pop();
        while (true)
        {
            T task;
            // 开始消费
            {
                lockGuard lockguard(tp->GetMutex());
                while (tp->IsEmpty())
                    tp->waitCond();
                // 一定有任务
                task = tp->GetTask();
                // 析构锁
            }

            task(td->_name);
            // cout << "线程，名字是：" << td->_name << endl;
            // sleep(1);
        }
    }

    void run()
    {
        for (auto &iter : _threads)
        {
            iter->start();
            // cout << iter->name() << "启动成功" << endl;
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }
    void pushTask(const T &task)
    {
        lockGuard lockguard(&_lock);

        _task_queue.push(task);
        // 唤醒
        pthread_cond_signal(&_cond);
    }

    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    vector<Thread *> _threads;
    int _num;
    queue<T> _task_queue;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;

    static ThreadPool<T> *_thread_ptr;
    static pthread_mutex_t _mutex;

    // 方案2:
    //  queue1,queue2
    //  std::queue<T>*p_queue, *c_queuell p_queue->queue1
    //  c_queue->queue2
    // p_queue ->生产一批任务之后，swap(p_queue,c_queue),唤醒所有线程/一个线程
    // 当消费者处理完毕的时候，你也可以进行swap(p_queue,c_queue)
    // 因为我们生产和消费用的是不同的队列，未来我们要进行资源的处理的时候，仅仅是指针
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_thread_ptr = nullptr; //_thread_ptr有且仅有一份
template <class T>
pthread_mutex_t ThreadPool<T>::_mutex = PTHREAD_MUTEX_INITIALIZER;

#endif